package view

import com.github.thomasnield.rxkotlinfx.observeOnFx
import com.github.thomasnield.rxkotlinfx.onChangedObservable
import com.github.thomasnield.rxkotlinfx.toMaybe
import com.jfoenix.controls.*
import entity.MyContract
import entity.PbcEbookEntity
import entity.PropertyValue
import entity.SysProperties
import io.reactivex.rxkotlin.toObservable
import io.reactivex.schedulers.Schedulers
import javafx.beans.property.BooleanProperty
import javafx.collections.FXCollections
import javafx.concurrent.Worker
import javafx.event.EventHandler
import javafx.scene.control.*
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.input.KeyCode
import javafx.scene.input.MouseEvent
import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill
import javafx.scene.layout.Priority
import javafx.scene.layout.StackPane
import javafx.scene.paint.Color
import javafx.scene.web.WebView
import javafx.stage.FileChooser
import javafx.stage.Screen
import presenter.MainPresenter
import tornadofx.*
import util.MyDbHelper
import util.MyDialogs
import util.MyWebUtil
import java.io.File
import java.io.FileInputStream
import java.util.*
import kotlin.math.absoluteValue

@Suppress("unused")
class MainWindow : View(MyContract.APP_MAIN_TITLE) {
    val mainPresenter: MainPresenter by inject()
    val loginView: LoginView by inject()
    lateinit var sysProperties: SysProperties

    override val root: StackPane by fxml()
    val searchTextField: JFXTextField by fxid("searchTextField")
    val treeView: JFXTreeView<PbcEbookEntity>
    val listView: JFXListView<PbcEbookEntity>
    val contentWebView: WebView by fxid("contentWebView")
    val drawerContainer: StackPane by fxid("drawerContainer")
    val splitPane: SplitPane by fxid("splitPane")
    val taggleIsSearchTitle: ToggleButton by fxid("taggleIsSearchTitle")
    val searchBtn: JFXButton by fxid("searchBtn")

    var startY = 0.0
    var downY = 0.0

    private lateinit var searchResultDrawerItem: DrawerItem

    val treeDatas = FXCollections.observableArrayList<PbcEbookEntity>()
    val treeExpandedStates = mutableListOf<Boolean>()


    init {

        val rectangle2d = Screen.getPrimary().visualBounds
        primaryStage.x = rectangle2d.minX
        primaryStage.y = rectangle2d.minY
        primaryStage.width = rectangle2d.width
        primaryStage.height = rectangle2d.height

        mainPresenter.requestDatas()

        taggleIsSearchTitle.apply {
            selectedProperty().addListener { _ ->
                if (!this.isSelected)
                    taggleIsSearchTitle.text = "按标题"
                else
                    taggleIsSearchTitle.text = "按内容"
            }
        }

        treeView = JFXTreeView<PbcEbookEntity>().apply {
            root = TreeItem(PbcEbookEntity(-1, "宝鸡支付", "宝鸡支付", true, ""))
            cellFormat {
                text = it.name
                graphic = if (it.is_dir) ImageView(Image(FileInputStream(MyContract.IMAGE_VIEW_FOLD_URL))) else ImageView(Image(FileInputStream(MyContract.IMAGE_VIEW_FILE_URL)))
                contextMenu = initContextMenu()
                treeItem.expandedProperty().addListener { observable, _, newValue ->
                    val bb: BooleanProperty = observable as BooleanProperty
                    val item: TreeItem<PbcEbookEntity> = bb.bean as TreeItem<PbcEbookEntity>
                    treeDatas.forEach {
                        if (it == item.value) {
                            treeExpandedStates[index] = newValue
                        }
                    }
                }
            }
            populate { setTreePopulate(it) }


        }


        listView = JFXListView<PbcEbookEntity>().apply {
            cellFormat {
                text = it.name
                isMouseTransparent = when {
                    it.content.isBlank() -> {
                        false
                    }
                    it.content == "1" -> true
                    else -> false
                }
            }
        }
        addItemClickListener()
        drawerContainer += drawer(multiselect = true){
            vboxConstraints {
                vgrow = Priority.ALWAYS
                hgrow = Priority.ALWAYS
                marginTop = 12.0
            }

            item("目录", showHeader = false, expanded = true) {
                this += treeView
            }

            searchResultDrawerItem = item("搜索结果", expanded = false) {
                this += listView
            }

//            treeDrawItem.expandedProperty.onChange {
//                if ((!treeDrawItem.expanded) && (!searchResultDrawerItem.expanded)) splitPane.items[0].hide()
//                else splitPane.items[0].show()
//            }
//            searchResultDrawerItem.expandedProperty.onChange {
//                if ((!treeDrawItem.expanded) && (!searchResultDrawerItem.expanded)) splitPane.items[0].hide()
//                else splitPane.items[0].show()
//            }
        }

        contentWebView.apply {

            engine.loadWorker.stateProperty().addListener { _, _, newValue ->
                if (newValue == Worker.State.SUCCEEDED) {
                    changeWebPageColorMode(sysProperties.colorMode)
                    letWebPageCannotBeCopied(sysProperties.defaultMode == MyContract.NORMAL_MODE)
                }
            }

            onMousePressed = EventHandler {
                if (it.eventType == MouseEvent.MOUSE_PRESSED) {
                    startY = it.y
                    downY = it.y
                }
            }
            onMouseReleased = EventHandler {
                if (it.eventType == MouseEvent.MOUSE_RELEASED) {
                    if (sysProperties.defaultMode != MyContract.NORMAL_MODE) {
                        if ((downY - it.y).absoluteValue < 5) {
                            if (it.y > this.height / 2) {
                                engine.executeScript("var currentpos=document.body.scrollTop+$height-10;window.scroll(0,currentpos);")
                            } else {
                                engine.executeScript("var currentpos=document.body.scrollTop-$height-10;window.scroll(0,currentpos);")
                            }
                        }
                    }
                }
            }
            onMouseDragged = EventHandler {
                if (sysProperties.defaultMode == MyContract.NORMAL_MODE) {
                } else {
                    val moveDes = (startY - it.y)
                    engine.executeScript("var currentpos=document.body.scrollTop;window.scroll(0,currentpos+${moveDes / 2});")
                    if (moveDes > 10) {
                        startY = it.y
                    }
                }
            }
        }

        searchTextField.setOnKeyPressed {
            if (it.code == KeyCode.ENTER) {
                searchClicked()
            }
        }
    }

    private fun addItemClickListener() {
        treeView.onUserSelect {

            log.info(it.content)

            if(it == treeView.root.value) {
                contentWebView.engine.load("file:${File(MyContract.FACE_PAGE_URL).absolutePath}")
            } else if (!it.content.isEmpty()) {
                val contentPath = if (File(it.content).exists()) File(it.content).absolutePath else ""
                contentWebView.engine.load("file:$contentPath")
            } else {
                val sonList = MyDbHelper.instance.selectPbcEbooksByFatherPath(it.path)
                contentWebView.engine.loadContent(MyWebUtil.getSonListHtml(it, sonList))
            }
        }

        listView.selectionModel.selectedItems.onChangedObservable().switchMap { it.toObservable() }
                .observeOnFx()
                .subscribe {
                    val contentPath = if (File(it.content).exists()) File(it.content).absolutePath else ""
                    val url = "file:$contentPath"
                    contentWebView.engine.load(url)

                    contentWebView.engine.loadWorker.stateProperty().addListener { ov, oldStatus, newStatus ->
                        if (newStatus == Worker.State.SUCCEEDED) {
                            val highLishtKeyWordsScript = "var re = new RegExp(\"${searchTextField.text}\", 'g');var allSpan = document.getElementsByTagName('body');for(var i = 0; i < allSpan.length; i++) {var oneSpan = allSpan[i];var textSpan = oneSpan.innerHTML;if(re.test(textSpan)){textSpan = textSpan.replace(re,\"<span style='background:yellow'>\$&</span>\");oneSpan.innerHTML = textSpan;}}"
                            contentWebView.engine.executeScript(highLishtKeyWordsScript)
                        }
                    }
                }
    }

    fun modeChooseClicked() {
        currentWindow?.let { MyDialogs.modeChooseDialog(root, it, sysProperties, this) }
    }

    fun dataManagerClicked() {
        currentWindow?.let { MyDialogs.dataManagerDialog(root, it, sysProperties, this) }
    }

    fun sysSettingClicked() {
        currentWindow?.let { MyDialogs.settingDialog(root, it, sysProperties, this) }
    }

    fun helpClicked() {
        find(HelpView::class).openWindow()
    }

    fun aboutClicked() {
        find(AboutView::class).openWindow()
    }

    fun exitClicked() {
        System.exit(0)
    }

    fun searchClicked() {

        listView.items.clear()
        val searchText = searchTextField.text

        if (searchText.trim().isEmpty()) return

        if (taggleIsSearchTitle.isSelected) {
            mainPresenter.searchKeyWordsInContent(searchText)
        } else {
            mainPresenter.searchKeyWordsInName(searchText)
        }
    }


    private fun initContextMenu() = ContextMenu().apply {
        item("添加文件").action {
            val importFiles = MyDialogs.chooseDocsFileDialog()
            mainPresenter.addNewBooks(importFiles, treeView.selectionModel.selectedItem.value.path)
        }
        item("添加目录").action {
            addDir()
        }
        separator()
        item("重命名").action {
            reName()
        }

//        item("重新添加内容").action {
//            // 目前只能重新上传文件
//            val importFiles = MyDialogs.chooseDocFileDialog()
//            if (importFiles.size == 1)
//                mainPresenter.updateBookById(importFiles[0], treeView.selectionModel.selectedItem.value, treeView.selectionModel.selectedItem.value.is_dir)
//        }

        item("上移").action {
            val selectedItem = treeView.selectionModel.selectedItem.value

            var upItem: PbcEbookEntity? = null
            val selectIndex = treeDatas.indexOf(selectedItem)
            var index2 = -1
            var currentIndex = selectIndex - 1
            while (currentIndex >=0) {
                if (treeDatas[currentIndex].path.split("/").size ==
                        selectedItem.path.split("/").size) {
                    upItem = treeDatas[currentIndex]
                    index2 = currentIndex
                    break
                }
                currentIndex --
            }

            if (index2 != -1)
                Collections.swap(treeExpandedStates, selectIndex, index2)

            upItem?.let { mainPresenter.exchangeTwoEbooks(selectedItem, it) }
        }

        item("下移").action {
            val selectedItem = treeView.selectionModel.selectedItem.value

            var downItem: PbcEbookEntity? = null
            val selectIndex = treeDatas.indexOf(selectedItem)
            var index2 = -1
            var currentIndex = selectIndex + 1
            while (currentIndex < treeDatas.size) {
                if (treeDatas[currentIndex].path.split("/").size ==
                        selectedItem.path.split("/").size) {
                    downItem = treeDatas[currentIndex]
                    index2 = currentIndex
                    break
                }
                currentIndex ++
            }

            if (index2 != -1)
                Collections.swap(treeExpandedStates, selectIndex, index2)

            downItem?.let { mainPresenter.exchangeTwoEbooks(selectedItem, it) }
        }

        item("删除").action {
            val deletedBook = treeView.selectionModel.selectedItem.value
            mainPresenter.removeEbooks(deletedBook)
            val deletedIndex = treeDatas.indexOf(deletedBook)
            treeExpandedStates.removeAt(deletedIndex)
        }
    }

    private fun reName() {
        val oldName = treeView.selectionModel.selectedItem.value.name
        TextInputDialog(oldName).apply {
            title = "重命名"
            contentText = "重命名"
            headerText = null
            icon = null
        }.toMaybe().toObservable().filter { it.trim() != "" && it != oldName }
                .observeOn(Schedulers.io())
                .subscribe {
                    val selectedItem = treeView.selectionModel.selectedItem

                    if (treeView.root == selectedItem) {
                        treeView.root.value.name = it
                        treeView.refresh()
                        sysProperties.rootName = it
                        mainPresenter.setSysProperties(sysProperties)
                    } else {
                        mainPresenter.updateBookName(it, selectedItem.value)
                    }
                }
    }

    private fun addDir() {
        MyDialogs.addDirDialog()
                .toMaybe()
                .toObservable()
                .filter { it.trim() != "" }
                .observeOn(Schedulers.io())
                .doOnNext {
                    mainPresenter.addNewFold(it, treeView.selectionModel.selectedItem.value.path)
                }
                .observeOnFx()
                .subscribe {  }
    }

    fun addNewBooksToUI(addedBooks: List<PbcEbookEntity>?) {

        addedBooks?.let {
            treeDatas.addAll(it)
            it.forEach {
                treeExpandedStates.add(false)
            }
        }
        treeView.populate { setTreePopulate(it) }
        treeViewExpanded(treeView.root)
    }

    fun addNewFoldToUI(addedFolder: PbcEbookEntity) {
        treeDatas.addAll(addedFolder)

        treeExpandedStates.add(false)

        treeView.populate { setTreePopulate(it) }
        treeViewExpanded(treeView.root)

        Alert(Alert.AlertType.CONFIRMATION).apply {
            headerText = null
            contentText = "是否为此目录添加页面？"
        }.toMaybe()
                .filter {
                    it == ButtonType.OK
                }
                .map {
                    chooseFile(
                            title = "选择文件导入",
                            mode = FileChooserMode.Single,
                            filters = arrayOf(
                                    FileChooser.ExtensionFilter("Doc","*.doc"),
                                    FileChooser.ExtensionFilter("All File","*.*"))
                    )
                }
                .filter { it.size == 1 }
                .subscribe {
                    mainPresenter.updateBookById(it[0], addedFolder, true)
                }
    }

    fun updateBookChangeToUI(oldBook: PbcEbookEntity, newBooks: List<PbcEbookEntity>?) {
        treeDatas.forEach {
            if (it == oldBook) {
                it.idProperty().value = newBooks?.get(0)?.id
                it.nameProperty().value = newBooks?.get(0)?.name
                it.pathProperty().value = newBooks?.get(0)?.path
                it.is_dirProperty().value = newBooks?.get(0)?.is_dir
                it.contentProperty().value = newBooks?.get(0)?.content
            }
        }
        treeView.refresh()
    }


    /**
     * Refresh view by properties.
     */
    fun refreshViewFromProPerties(sysProperties: SysProperties) {
        this.sysProperties = sysProperties

        treeView.root.value.name = sysProperties.rootName

        when(sysProperties.defaultMode) {
            PropertyValue.ModeValue.VALUE_VIEW_MODE -> toViewMode()
            PropertyValue.ModeValue.VALUE_NORMAL_MODE -> toNormalMode()
            PropertyValue.ModeValue.VALUE_EDIT_MODE -> toEditMode()
        }
    }

    /**
     * Switch to View Mode.
     */
    fun toViewMode() {
        hideMenu()
        becomeFullScreen()
        sysProperties.defaultMode = MyContract.VIEW_MODE
    }

    /**
     * Switch to Normal Mode.
     */
    fun toNormalMode() {
        leaveFullScreen()
        showMenu()
        sysProperties.defaultMode = MyContract.NORMAL_MODE
    }
    /**
     * BeCome into Edit Mode.
     */
    fun toEditMode() {
        toNormalMode()
        sysProperties.defaultMode = MyContract.EDIT_MODE
    }

    /**
     * Become full screen.
     */
    private fun becomeFullScreen() {
        primaryStage.isFullScreen = true
        currentStage?.isFullScreen = true
    }

    /**
     * Leave full screen mode.
     */
    private fun leaveFullScreen() {
        primaryStage.isFullScreen = false
        currentStage?.isFullScreen = false
    }

    /**
     * Show tool menu.
     */
    private fun showMenu() {
//        root.top.show()
    }

    /**
     * Hide tool menu.
     */
    private fun hideMenu() {
//        root.top.hide()
    }

    private fun initTreeExpandedStates() {
        treeDatas.forEach {
            treeExpandedStates.add(false)
        }
    }

    private var isLogin = false

    fun loadTreeView(getedEbooks: List<PbcEbookEntity>) {
        treeDatas.setAll(getedEbooks)

        if (treeExpandedStates.size <= 0)
            initTreeExpandedStates()

        treeView.populate { setTreePopulate(it) }

        treeView.selectionModel.select(treeView.root)
        treeViewExpanded(treeView.root)
    }

    private fun setTreePopulate(p: TreeItem<PbcEbookEntity>) =
        if (p == root) {
            treeDatas.filter {
                it.path.split("/").size == 2
            }
        } else {
            treeDatas.filter {
                val childrenFatherPath = it.path.substring(0, it.path.lastIndexOf("/"))
                p.value.path == childrenFatherPath
            }
        }

    fun saveSysProperties(sysProperties: SysProperties) {
        mainPresenter.setSysProperties(sysProperties)
    }
    fun changeWebPageColorMode(it: String) {

        when(it){
            MyContract.NORMAL_COLOR_MODE -> {
                changeWebPageBgColor("white")
                changeWebPageTxtColor("black")
                root.background = Background(BackgroundFill(Color.WHITE, null, null))
            }
            MyContract.NIGHT_COLOR_MODE -> {
                changeWebPageBgColor("black")
                changeWebPageTxtColor("white")
                root.background = Background(BackgroundFill(Color.BLACK, null, null))
            }
            MyContract.REAL_COLOR_MODE -> {
                changeWebPageBgColor("#F1E5C9")
                changeWebPageTxtColor("#0E1A36")
                root.background = Background(BackgroundFill(Color.valueOf("#F1E5C9"), null, null))
            }
        }
    }
    private fun letWebPageCannotBeCopied(canBeSelected: Boolean) {
        if (contentWebView.engine.loadWorker.state == Worker.State.SUCCEEDED) {
            contentWebView.engine.executeScript(
                    "document.body.onmousedown = function(){return $canBeSelected;};" +
                            "document.oncontextmenu = function(){return $canBeSelected;};")
        }
    }

    private fun changeWebPageBgColor(backgroundColorStr: String) {
        if (contentWebView.engine.loadWorker.state == Worker.State.SUCCEEDED)
            contentWebView.engine.executeScript(
                    "document.getElementsByTagName('body')[0].style.backgroundColor = '$backgroundColorStr';")
    }

    private fun changeWebPageTxtColor(txtColorStr: String) {
        if (contentWebView.engine.loadWorker.state == Worker.State.SUCCEEDED)
            contentWebView.engine.executeScript(
                    "var spanTag = document.getElementsByTagName('span');" +
                            "for(i=0;i<spanTag.length;i++){spanTag[i].style.color='$txtColorStr'}")
    }

    fun addSearchResultToList(resultList: List<PbcEbookEntity>?, searchText: String, isSearchName: Boolean) {
        resultList?.let { listView.items.addAll(it) }
        searchResultDrawerItem.expanded = true

    }
    private fun treeViewExpanded(treeItem: TreeItem<PbcEbookEntity>?) {
        if (treeItem != null && !treeItem.isLeaf) {

            val index = treeDatas.indexOf(treeItem.value)

            if (index != -1) {
                treeItem.isExpanded = treeExpandedStates[index]
            }

            treeItem.children.forEach { treeViewExpanded(it) }
        }


    }
}



